﻿
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Nirvana
{
    public class CheckOrChangeUnityShader
    {
        public enum MatType
        {
            Standard = 0,
            ParticleSystem = 1,
            Sprite = 2,
            Normal = 3,
        }

        static CheckOrChangeUnityShader self;
        static Material replacedStandardMat;
        static Material replacedSpriteMat;
        static Material replacedParticleSystemMat;
        static Dictionary<MatType, Material> typeAndMaterial;

        static List<Shader> shadersInProject;
        static List<Material> matsInProject;

        static Dictionary<string, Shader> shaderNameAndShaders;
        static Dictionary<string, List<Material>> shaderNameAndMats;
        static Dictionary<string, List<Material>> wrongShaderNameAndMats;
        static List<string> NotFoundShaderList;

        static List<Material> sameNameMat;
        static List<Material> noEnvenSameNameMat;
        static List<Material> standardMat;

        public static void InitReplacedMats()
        {
            replacedStandardMat = AssetDatabase.LoadAllAssetsAtPath("Assets/Resources/BuildInShader/Default_Mat.mat")[0] as Material;
            replacedSpriteMat = AssetDatabase.LoadAllAssetsAtPath("Assets/Resources/BuildInShader/Default_Sprite.mat")[0] as Material;
            replacedParticleSystemMat = AssetDatabase.LoadAllAssetsAtPath("Assets/Resources/BuildInShader/Default_ParticleSystem.mat")[0] as Material;
            typeAndMaterial = new Dictionary<MatType, Material>();
            typeAndMaterial.Add(MatType.ParticleSystem, replacedParticleSystemMat);
            typeAndMaterial.Add(MatType.Sprite, replacedSpriteMat);
            typeAndMaterial.Add(MatType.Standard, replacedStandardMat);
            typeAndMaterial.Add(MatType.Normal, replacedStandardMat);
            wrongShaderNameAndMats = new Dictionary<string, List<Material>>();

            shadersInProject = new List<Shader>();
            shaderNameAndShaders = new Dictionary<string, Shader>();
            matsInProject = new List<Material>();
            shaderNameAndMats = new Dictionary<string, List<Material>>();
            NotFoundShaderList = new List<string>();
            sameNameMat = new List<Material>();
            noEnvenSameNameMat = new List<Material>();
            standardMat = new List<Material>();
        }

        public static MatType GetReplacedMatType(Material srcMat)
        {
            if (srcMat == null)
            {
                return MatType.Standard;
            }
            else if (srcMat.name.Equals("Default-ParticleSystem")
                || srcMat.shader.name.Equals("Particles/Standard Unlit"))
            {
                return MatType.ParticleSystem;
            }
            else if (srcMat.name.Equals("Sprites-Default")
                || srcMat.shader.name.Equals("Sprites/Default"))
            {
                return MatType.Sprite;
            }
            else if (srcMat.name.Equals("Default-Material")
                || srcMat.shader.name.Equals("Standard"))
            {
                return MatType.Standard;
            }
            return MatType.Normal;
        }
   

        static void ClearShaderData()
        {
            shadersInProject = null;
            matsInProject = null;

            shaderNameAndShaders = null;
            shaderNameAndMats = null;
            wrongShaderNameAndMats = null;

            sameNameMat = null;
            noEnvenSameNameMat = null;
            standardMat = null;

            NotFoundShaderList = null;
        }

        //每个物体的检查和替换代码封装
        private static bool CheckAndReplaceObjectMats(ref GameObject obj)
        {
            MatType type = MatType.Normal;
            Renderer[] allRender = obj.GetComponentsInChildren<Renderer>(true);
            ParticleSystemRenderer[] allParticleSystemRenderers = obj.GetComponentsInChildren<ParticleSystemRenderer>(true);
            bool needSave = false;
            for (int j = 0; j < allRender.Length; j++)
            {
                Material[] srcMats = allRender[j].sharedMaterials;
                bool needSaveMats = false;
                if (srcMats != null)
                {
                    for (int k = 0; k < srcMats.Length; k++)
                    {
                        type = MatType.Normal;
                        if (GetReplacedMatType(srcMats[k]) != MatType.Normal)
                        {
                            needSaveMats = true;
                            needSave = true;
                            srcMats[k] = typeAndMaterial[type];
                        }
                    }
                    if (needSaveMats)
                    {
                        allRender[j].sharedMaterials = srcMats;
                    }
                }

            }

            for (int j = 0; j < allParticleSystemRenderers.Length; j++)
            {
                Material[] srcMats = allParticleSystemRenderers[j].sharedMaterials;
                if (srcMats != null)
                {
                    bool needSaveMats = false;
                    for (int k = 0; k < srcMats.Length; k++)
                    {
                        type = MatType.Normal;
                        if (GetReplacedMatType(srcMats[k]) != MatType.Normal)
                        {
                            needSaveMats = true;
                            needSave = true;
                            srcMats[k] = typeAndMaterial[type];
                        }
                    }
                    if (needSaveMats)
                    {
                        allParticleSystemRenderers[j].sharedMaterials = srcMats;
                    }
                }

                Material trailMat = allParticleSystemRenderers[j].trailMaterial;
                type = MatType.Normal;
                if (GetReplacedMatType(trailMat) != MatType.Normal)
                {
                    needSave = true;
                    allParticleSystemRenderers[j].trailMaterial = typeAndMaterial[type];
                }
            }

            return needSave;
        }

        #region SceneObject
        //所有场景中的所有物体中的内置的几种材质shader替换掉
        static void ChangeSceneObjDefaultMat()
        {
            string headPath = Application.dataPath;
            //eg:D:/Project/Test/
            headPath = headPath.Substring(0, headPath.IndexOf("Assets"));

            List<string> optimizedOriginalScenePaths = new List<string>();
           // TextureModifier.AddRootSourcePathToList("Assets/Snowstorm", headPath, "Scene", ref optimizedOriginalScenePaths); ///Env/Scenes

            for (int i = 0; i < optimizedOriginalScenePaths.Count; i++)
            {
                EditorUtility.DisplayProgressBar("ChangeSceneObjDefaultMat", "Scene -> " + optimizedOriginalScenePaths[i], i / optimizedOriginalScenePaths.Count);
                EditorSceneManager.OpenScene(optimizedOriginalScenePaths[i], OpenSceneMode.Single);
                GameObject[] gameObject = UnityEngine.Object.FindObjectsOfType<GameObject>();
                bool needSave = false;
                for (int k = 0; k < gameObject.Length; k++)
                {
                    needSave = CheckAndReplaceObjectMats(ref gameObject[k]);
                }

                if (needSave)
                {
                    EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
                }
            }
            EditorUtility.ClearProgressBar();
        }
        #endregion

        // 所有prefab检查修改
        [MenuItem("Assets/Shader/FixPrefabStandardShader")]
        static void FixPrefabStandardShader()
        {
            InitReplacedMats();
            Scene newScene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
            Lightmapping.giWorkflowMode = Lightmapping.GIWorkflowMode.OnDemand;

            Dictionary<string, bool> wrongStandardPrefabList = new Dictionary<string, bool>();
            Dictionary<string, bool> wrongSpritePrefabList = new Dictionary<string, bool>();
            Dictionary<string, bool> wrongParticleSystemPrefabList = new Dictionary<string, bool>();

            Dictionary<MatType, Dictionary<string, bool>> wrongPrefabList = new Dictionary<MatType, Dictionary<string, bool>>();
            wrongPrefabList.Add(MatType.ParticleSystem, wrongParticleSystemPrefabList);
            wrongPrefabList.Add(MatType.Sprite, wrongSpritePrefabList);
            wrongPrefabList.Add(MatType.Standard, wrongStandardPrefabList);

            bool needSave = false;

           // List<Material> ms = new List<Material>();
            GameObject prefabObj = null;

            string[] prefabGUIDArray = AssetDatabase.FindAssets("t:prefab", new string[1] { "Assets" });
            for (int i = 0; i < prefabGUIDArray.Length; i++)
            {
                string path = AssetDatabase.GUIDToAssetPath(prefabGUIDArray[i]);
                var asset = AssetDatabase.LoadAssetAtPath<GameObject>(path);
                if (asset == null)
                {
                    continue;
                }

                prefabObj = PrefabUtility.InstantiatePrefab(asset, SceneManager.GetActiveScene()) as GameObject;
                EditorUtility.DisplayProgressBar("FixPrefabStandardShader", "Prefab -> " + prefabObj.name, i / prefabGUIDArray.Length);

                needSave = CheckAndReplaceObjectMats(ref prefabObj);

                if (needSave)
                {
                    PrefabUtility.SaveAsPrefabAsset(prefabObj, path);
                }
            }
            EditorUtility.ClearProgressBar();
            Scene scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);

        }

    }
}
